package com.feicheng.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.feicheng.common.constant.Constant;
import com.feicheng.common.exception.SystemException;
import com.feicheng.common.message.LoginMessage;
import com.feicheng.common.result.ResultInfo;
import com.feicheng.common.wx.WxHTTPInterface;
import com.feicheng.persistence.entity.Account;
import com.feicheng.persistence.entity.Client;
import com.feicheng.persistence.entity.Store;
import com.feicheng.persistence.entity.StoreClient;
import com.feicheng.persistence.entity.StoreWx;
import com.feicheng.persistence.entity.WxServer;
import com.feicheng.persistence.service.IAccountService;
import com.feicheng.persistence.service.IClientService;
import com.feicheng.persistence.service.IStoreClientService;
import com.feicheng.persistence.service.IStoreService;
import com.feicheng.persistence.service.IStoreWxService;
import com.feicheng.persistence.service.IWxServerService;
import com.feicheng.service.BaseService;
import com.feicheng.service.IFLoginService;

/**
 * @see com.feicheng.service.IFLoginService
 */
@Service
public class FClientWxCodeLoginServiceImpl extends BaseService implements IFLoginService {

    @Autowired
    LoginMessage loginMessage;

    @Autowired
    WxHTTPInterface wxHTTPInterface;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    IStoreService storeService;

    @Autowired
    IClientService clientService;

    @Autowired
    IAccountService accountService;

    @Autowired
    IStoreClientService storeClientService;

    @Autowired
    IStoreWxService storeWxService;

    @Autowired
    IWxServerService wxServerService;

    /**
     * 登录
     *
     * @param loginParams 登录参数
     * @return
     */
    @Transactional
    @Override
    public ResultInfo login(String loginParams) {
        JSONObject result = new JSONObject();
        /* 取得登录所需的参数 jscode ，转换出现问题时抛出异常，登录逻辑停止。*/
        JSONObject param = null;
        try {
            param = JSONObject.parseObject(loginParams);
        } catch (JSONException exception) {
            throw new SystemException(loginMessage.getE01());
        }

        String code = param.getString(Constant.WX.PARAM.CODE);
        Integer storeId = param.getInteger(Constant.ENTITY.STORE.STORE_ID);

        Store store = storeService.getById(storeId);

        QueryWrapper<StoreWx> storeWxQueryWrapper = new QueryWrapper<StoreWx>();
        storeWxQueryWrapper.eq(Constant.ENTITY.STORE_WX.STORE_ID, storeId);
        List<StoreWx> storeWxList = storeWxService.list(storeWxQueryWrapper);

        if (0 == storeWxList.size()) {
            throw new SystemException(loginMessage.getE08());
        }

        JSONArray wxIds = new JSONArray();
        for (StoreWx sw : storeWxList) {
            wxIds.add(sw.getWId());
        }

        QueryWrapper<WxServer> wxServerQueryWrapper = new QueryWrapper<WxServer>();
        wxServerQueryWrapper.in(Constant.ENTITY.WX_SERVER.W_ID, wxIds);
        wxServerQueryWrapper.eq(Constant.ENTITY.WX_SERVER.WX_TYPE, Constant.VAL.WX_TYPE.Y);
        List<WxServer> wxServerList = wxServerService.list(wxServerQueryWrapper);

        if (0 == wxServerList.size()) {
            throw new SystemException(loginMessage.getE08());
        }

        WxServer wxServer = wxServerList.remove(0);
        StringBuilder sbUrlAccessToken = new StringBuilder();
        sbUrlAccessToken.append(wxHTTPInterface.getAccessToken())
                .append(Constant.WX.PARAM.APPID).append(Constant.HTTP.REQUEST.EQ).append(wxServer.getAppId())
                .append(Constant.HTTP.REQUEST.AD).append(Constant.WX.PARAM.SECRET).append(Constant.HTTP.REQUEST.EQ).append(wxServer.getAccessKey())
                .append(Constant.HTTP.REQUEST.AD).append(Constant.WX.PARAM.CODE).append(Constant.HTTP.REQUEST.EQ).append(code)
                .append(Constant.HTTP.REQUEST.AD).append(Constant.WX.PARAM.GRANT_TYPE).append(Constant.HTTP.REQUEST.EQ).append(Constant.WX.VALUE.AUTHORIZATION_CODE);

        ResponseEntity<String> resultAccessToken = restTemplate.getForEntity(sbUrlAccessToken.toString(), String.class);

        JSONObject resAccessToken = JSONObject.parseObject(resultAccessToken.getBody());
        if (resAccessToken.containsKey(Constant.WX.RESPONSE.ERRCODE)) {
            throw new SystemException(resAccessToken.getString(Constant.WX.RESPONSE.ERRMSG));
        }

        String openId = resAccessToken.getString(Constant.WX.RESPONSE.OPENID);
        if (!StringUtils.hasLength(openId)) {
            throw new SystemException(loginMessage.getE05());
        }

        QueryWrapper<StoreClient> storeClientQueryWrapper = new QueryWrapper<StoreClient>();
        storeClientQueryWrapper.eq(Constant.ENTITY.STORE_CLIENT.STORE_ID, storeId);
        storeClientQueryWrapper.eq(Constant.ENTITY.STORE_CLIENT.OPEN_ID, openId);
        storeClientQueryWrapper.eq(Constant.ENTITY.STORE_CLIENT.WX_TYPE, Constant.VAL.WX_TYPE.S);
        
        synchronized (openId.intern()) {
        	List<StoreClient> storeClientList = storeClientService.list(storeClientQueryWrapper);

	        if (0 == storeClientList.size()) {
	            StringBuilder sbUrlUserInfo = new StringBuilder();
	            sbUrlUserInfo.append(wxHTTPInterface.getUserInfo())
	                    .append(Constant.WX.PARAM.ACCESS_TOKEN).append(Constant.HTTP.REQUEST.EQ).append(resAccessToken.getString(Constant.WX.RESPONSE.ACCESS_TOKEN))
	                    .append(Constant.HTTP.REQUEST.AD).append(Constant.WX.PARAM.OPENID).append(Constant.HTTP.REQUEST.EQ).append(openId)
	                    .append(Constant.HTTP.REQUEST.AD).append(Constant.WX.PARAM.LANG).append(Constant.HTTP.REQUEST.EQ).append(Constant.WX.VALUE.ZH_CN);
	
	            ResponseEntity<String> resultUserInfo = restTemplate.getForEntity(sbUrlUserInfo.toString(), String.class);
	
	            JSONObject restUserInfo = JSONObject.parseObject(resultUserInfo.getBody());
	            if (restUserInfo.containsKey(Constant.WX.RESPONSE.ERRCODE)) {
	                throw new SystemException(loginMessage.getE05());
	            }
	
	            String nickName = restUserInfo.getString(Constant.WX.RESPONSE.NICK_NAME);
	            Boolean sex = (0 == restUserInfo.getInteger(Constant.WX.RESPONSE.SEX));
	            String headImgUrl = restUserInfo.getString(Constant.WX.RESPONSE.HEAD_IMG_URL);
	
	            Client client = new Client();
	            client.setClientName(nickName);
	            client.setSex(sex);
	            client.setHeadImgUrl(headImgUrl);
	            clientService.save(client);
	
	            StoreClient sc = new StoreClient();
	            sc.setClientId(client.getClientId());
	            sc.setOpenId(openId);
	            sc.setStoreId(storeId);
	            sc.setWxType(Constant.VAL.WX_TYPE.S);
	            storeClientService.save(sc);
	
	            Account account = new Account();
	            account.setClientId(client.getClientId());
	            account.setDepositAmount(0);
	            account.setTimeLongs(0);
	            accountService.save(account);
	
	            result.put(Constant.WX.RESPONSE.ACCESS_TOKEN, resAccessToken);
	            result.put(Constant.WX.RESPONSE.USER_INFO, restUserInfo);
	            result.put(Constant.ENTITY.CLIENT.TABLE, client);
	            result.put(Constant.ENTITY.STORE_CLIENT.TABLE, sc);
	            result.put(Constant.ENTITY.ACCOUNT.TABLE, account);
	
	        } else if (1 == storeClientList.size()) {
	            StoreClient sc = storeClientList.remove(0);
	            Client client = clientService.getById(sc.getClientId());
	
	            QueryWrapper<Account> accountQueryWrapper = new QueryWrapper<Account>();
	            accountQueryWrapper.eq(Constant.ENTITY.ACCOUNT.CLIENT_ID, client.getClientId());
	            List<Account> accountList = accountService.list(accountQueryWrapper);
	
	            if (1 != accountList.size()) {
	                throw new SystemException(loginMessage.getE05());
	            }
	
	            result.put(Constant.ENTITY.CLIENT.TABLE, client);
	            result.put(Constant.ENTITY.STORE_CLIENT.TABLE, sc);
	            result.put(Constant.ENTITY.ACCOUNT.TABLE, accountList.remove(0));
	        }
        
        }
        result.put(Constant.ENTITY.STORE.TABLE, store);
        return ResultInfo.success(result);
    }
}
